home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / gpp-1_42.lha / g++-1.42.0 / collect3.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  12KB  |  427 lines

  1. /* 
  2.  * Copyright (C) 1991 Free Software Foundation, Inc.
  3.  * collect3.c - derived from collect2.c by Heinz Seidl (hgs@cygnus.com).
  4.  */
  5.  
  6. /*
  7.   This file is part of GNU CC.
  8.   
  9.   GNU CC is free software; you can redistribute it and/or modify
  10.   it under the terms of the GNU General Public License as published by
  11.   the Free Software Foundation; either version 2, or (at your option)
  12.   any later version.
  13.   
  14.   GNU CC is distributed in the hope that it will be useful,
  15.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.   GNU General Public License for more details.
  18.   
  19.   You should have received a copy of the GNU General Public License
  20.   along with GNU CC; see the file COPYING.  If not, write to
  21.   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. /*
  24.   C++ allows to initialize global variables with arbitrary expressions, 
  25.   in particular with constructors. This means, that arbitrary pieces of
  26.   code have to be executed _before_ `main()' is called and that constructed
  27.   objects must be destructed at the end of the program before `exit()' is
  28.   called.
  29.   
  30.   For each file with global initialization gcc generates now initialization
  31.   and finalization code:
  32.   
  33.   The initialization code has the label: `__GLOBAL_$I$<name>', where <name> is
  34.   the name of the first variable to be initialized.
  35.   The finitialization code has the label: `__GLOBAL_$D$<name>', where <name> 
  36.   is the name of the first variable to be destructed.
  37.   
  38.   Since the C runtime system (and the UNIX linkers) don't know about this kind
  39.   of initialization, we have to deal with them:
  40.   
  41.   This program "collects" all the entrypoints for initialization and 
  42.   finalization code and associates them with the labels `__CTOR_LIST__' and
  43.   `__DTOR_LIST__' respectively.
  44.   
  45.   Gcc generates code for the call to `main()' witch invokes the initialization
  46.   and finalization code.
  47.   */
  48.  
  49.  
  50. /* 
  51.  * The __C/DTOR_LIST__ have the folowing form:
  52.  * 
  53.  * entry_pt * __C/DTOR_LIST__[] = {
  54.  *    _first_entry_point,
  55.  *    _second_entry_point,
  56.  *    ...
  57.  *    0
  58.  * }
  59.  *
  60.  * Both lists are in _proper_ order; i.e. the destructor list is in reverse
  61.  * order of the constructor list.
  62.  *
  63.  * In case OLD_FORMAT is defined, init.c understands the format generated by
  64.  * gld 1.x and used by gnulib3.
  65.  *
  66.  * The order is determined by the order of the .o files on the command line
  67.  * and how the linker arranges them in the output file.
  68.  * It is expected that the linker arranges the con/destructors in reverse
  69.  * order as the command line.
  70.  * There is no predicable order for files from archives.
  71.  */
  72.  
  73. static char * rcsId = "$Id: collect3.c,v 1.2 1991/10/03 00:37:07 hgs Exp $";
  74.  
  75. #if defined (__GNUC__)
  76. #define alloca __builtin_alloca
  77. #else
  78. #define alloca malloc
  79. #endif
  80.  
  81. #include "config.h"
  82.  
  83.  /* This means no additional `_' is prepended; 
  84.     but have at least one `_' at the beginning */
  85. #ifdef NO_UNDERSCORES
  86. #define CTOR_MARKER_NAME     "_GLOBAL_$I$"
  87. #define DTOR_MARKER_NAME     "_GLOBAL_$D$"
  88. #define CDTOR_MARKER_LEN     11
  89. #define FUNCTION_LIST_ADDR     "_function_list_addr"
  90. #define FUNCTION_LIST_ADDR_LEN     19
  91. #else
  92. #define CTOR_MARKER_NAME     "__GLOBAL_$I$"
  93. #define DTOR_MARKER_NAME     "__GLOBAL_$D$"
  94. #define CDTOR_MARKER_LEN     12
  95. #define FUNCTION_LIST_ADDR     "__function_list_addr"
  96. #define FUNCTION_LIST_ADDR_LEN     20
  97. #endif
  98.  
  99. #include <stdio.h>
  100.  
  101. #define USAGE()  do fprintf( stderr, \
  102.                 "Usage: %s <link-command options>" ##            \
  103.                 "[-- [-t] [-d tmp_dir] [-g gcc-path]]",          \
  104.                 argv[0]);                                        \
  105.   while(0);
  106.  
  107. #define GREP_CMD " grep -v TOR_LIST__"
  108. #define NM_CMD   " nm -pg"
  109.  
  110. /* convert empty string into blank (stupidity of ?printf) */
  111. #define S(str) ((str && *str) ? str : " ")
  112.  
  113. extern char *mktemp (char *template);
  114.  
  115. static void error( const char * msg, int line );
  116. #define ERROR(msg) error( msg, __LINE__)
  117.  
  118. #ifndef PREFIX
  119. #define PREFIX "/usr/unsupported"
  120. #endif
  121.  
  122. #define const static
  123. /* causes strange bugs */
  124. const char * TMP_DIR   = "/usr/tmp";
  125. const char * AOUTXXX   = "AOUTXXXXXX";
  126. const char * CDTORXXX  = "CDTORXXXXXX";
  127. const char * GCC_FLAGS = "-g -ftraditional";
  128. const char * GCC       = PREFIX "/bin/gcc";
  129. #undef const
  130.  
  131. static char * prog_name = NULL;
  132.  
  133. /* Linked lists of constructor and destructor names.
  134.  */
  135. struct id 
  136. {
  137.     char *name;
  138.     struct id *next;
  139. };
  140.  
  141. /* if we link ccrt0 to an object we always need the C/DTOR_LISTS even if they are empty */
  142. static int need_cdtor_list = 0;
  143.  
  144. main (int argc, char *argv[])
  145. {
  146.     char /*const causes strange errors*/* tmp_dir = TMP_DIR;
  147.     char CDTOR_filename_c[BUFSIZ], CDTOR_filename_o[BUFSIZ], buf[BUFSIZ];
  148.     char AOUT_filename[BUFSIZ];
  149.     FILE * pipe_in;
  150.     char * outfile = "a.out";
  151.     char * arg, ldargs1[BUFSIZ*2], ldargs2[BUFSIZ*2], cmd[BUFSIZ*4];
  152.     char * s = ldargs1;
  153.     char * debug_str = NULL;    /* or `set -x; ' */
  154.     int    no_rm = 0; 
  155.     char /* const */* gcc = GCC;
  156.     int    ret = 0;
  157.     
  158.     ldargs1[0] = '\0'; ldargs2[0] = '\0';
  159.     
  160.     prog_name = argv[0];
  161.     /* Parse arguments for the linker
  162.      */
  163.     while (arg = *++argv)
  164.       {
  165.       if (! strcmp (arg, "--"))
  166.         {
  167.         /* parse the options for collect
  168.          */
  169.         while (arg = *++argv)
  170.           {
  171.               switch  ( (int) arg[1]) 
  172.             {
  173.               case 'v':
  174.                 debug_str = "set -x;";
  175.                 tmp_dir = ".";
  176.                 break;
  177.               case 'd':
  178.                 tmp_dir = *++argv;
  179.                 break;
  180.               case 'g':
  181.                 gcc = *++argv;
  182.                 break;
  183.               case 'r':
  184.                 no_rm = 1;
  185.                 tmp_dir = ".";
  186.                 break;
  187.               default:
  188.                 USAGE();
  189.                 exit(1);
  190.             }
  191.           }
  192.         break;        /* get out of arg parsing loop */
  193.         }
  194.       
  195.       
  196.       /* remove output file from command line
  197.        */
  198.       if (! strcmp (arg, "-o"))
  199.         {
  200.         outfile = *++argv;
  201.         continue;
  202.         }
  203.       
  204.       /* Split the arguments after *rt0.o and before the first .o file 
  205.        */
  206.       if ( !strcmp (arg + strlen(arg) -2, ".o") )
  207.         if (! (strlen( arg) >= 5 && !strcmp (arg+strlen(arg)-5, "rt0.o")) )
  208.           s = ldargs2;
  209.       
  210.       strcat (s , " '"); strcat (s, arg); strcat (s, "'");
  211.       }
  212.     
  213.     /* Make temp file names.
  214.      */
  215.     if (debug_str)
  216.       {
  217.       tmp_dir = ".";
  218.       sprintf( AOUT_filename, "%s", AOUTXXX);
  219.       (void) mktemp (AOUT_filename);
  220.       }
  221.     else
  222.       sprintf( AOUT_filename, "%s", outfile); /* we reuse the outfile */
  223.     
  224.     sprintf( buf, "%s/%s", tmp_dir, CDTORXXX);
  225.     (void) mktemp (buf);
  226.     sprintf (CDTOR_filename_c, "%s.c", buf);
  227.     sprintf (CDTOR_filename_o, "%s.o", buf);
  228.     
  229.     
  230.     
  231.     /* Load the program, searching all libraries.
  232.      * (The introduction of shared libraries fucked the -r option of
  233.      * the SunOS linker; therefore we link twice; unless we don't have 
  234.      * de/constructors).
  235.      */
  236.     if ( debug_str)
  237.       sprintf (cmd, "%s ld -o %s %s %s",
  238.            S(debug_str), AOUT_filename, S(ldargs1), S(ldargs2));
  239.     else
  240.       sprintf (cmd, "ld -o %s %s %s 2>&1 |" GREP_CMD,
  241.            AOUT_filename, S(ldargs1), S(ldargs2));
  242.     system( cmd);
  243.     
  244.     /* Examine the namelist with nm and search it for static constructors
  245.      * and destructors to call.
  246.      * Write the constructor and destructor tables to a .c file.
  247.      */
  248.     sprintf (cmd, "%s " NM_CMD " %s", S(debug_str), AOUT_filename);  
  249.     if (! (pipe_in = popen (cmd, "r"))) ERROR( "popen failed");
  250.     
  251.     ret = write_CDTOR_list (pipe_in, CDTOR_filename_c);
  252.     
  253.     if (pclose (pipe_in)) ERROR( "pclose failed");
  254.     
  255.     if ( ret == 0 && ! need_cdtor_list) exit(0);       /* no de/constructors */
  256.     
  257.     /* Compile the constructor and destructor tables.
  258.      */
  259.     if ( debug_str )
  260.       sprintf (cmd, "%s %s -v -c %s -o %s %s",
  261.            S(debug_str), gcc, GCC_FLAGS,
  262.            CDTOR_filename_o, CDTOR_filename_c);
  263.     else
  264.       sprintf (cmd,"%s -c %s -o %s %s",
  265.            gcc, GCC_FLAGS, CDTOR_filename_o, CDTOR_filename_c);
  266.     system( cmd);
  267.     
  268.     /* Link the tables in with the rest of the program.
  269.      */
  270.     sprintf (cmd, "%s ld -o %s %s %s %s",
  271.          S(debug_str), outfile, S(ldargs1), CDTOR_filename_o,
  272.          S(ldargs2));
  273.     system( cmd);
  274.     
  275.     if ( ! debug_str && ! no_rm)
  276.       {
  277.       unlink (CDTOR_filename_c);
  278.       unlink (CDTOR_filename_o);
  279.       }
  280.     
  281.     exit(0);
  282. }
  283.  
  284. int  write_CDTOR_list (FILE * pipe_in, char * CDTOR_filename_c)
  285.      /*
  286.       * Scan the name list of the loaded program for the symbols g++ uses
  287.       * for static constructors and destructors.  Write their addresses
  288.       * into tables which __main() and exit() will call.
  289.       * returns 0 iff no de/constructors - otherwise > 0
  290.       */
  291. {
  292.     register char *p;
  293.     char buf[BUFSIZ];
  294.     struct id *newid;
  295.     FILE * CDTOR_file;
  296.     
  297.     struct id *constructors = 0;
  298.     struct id *destructors = 0, *d_anchor = 0;
  299. #ifdef OLD_FORMAT
  300.     int nb_constructors = 0, nb_destructors = 0;
  301. #endif
  302.     
  303.     while (! feof (pipe_in))
  304.       {
  305.       /* read a line and strip trailing newline */
  306.       fgets (buf, sizeof buf, pipe_in);
  307.       p = buf + strlen( buf) - 1;
  308.       if ( *p == '\n') *p = '\0'; 
  309.       
  310.       /* If it contains a constructor or destructor name, add the name
  311.        * to the appropriate list.
  312.        */
  313.       for (p = buf; *p && *p != '_'; p++);
  314.       
  315.       if (! strncmp (p, CTOR_MARKER_NAME, CDTOR_MARKER_LEN))
  316.         {
  317.         newid = alloca (sizeof *newid);
  318.         newid->name = alloca (strlen (p) + 1);
  319. #ifdef NO_UNDERSCORES
  320.         strcpy (newid->name, p);
  321. #else
  322.         strcpy (newid->name, p+1);
  323. #endif
  324.         newid->next = constructors;
  325.         constructors = newid;
  326. #ifdef OLD_FORMAT
  327.         nb_constructors ++;
  328. #endif
  329.         }
  330.       else if (! strncmp (p, DTOR_MARKER_NAME, CDTOR_MARKER_LEN))
  331.         {
  332.         newid = alloca (sizeof *newid);
  333.         newid->name = alloca (strlen (p) + 1);
  334. #ifdef NO_UNDERSCORES
  335.         strcpy (newid->name, p);
  336. #else
  337.         strcpy (newid->name, p+1);
  338. #endif
  339. #ifdef OLD_FORMAT
  340.         newid->next = destructors;
  341.         destructors = newid;
  342.         nb_destructors ++;
  343. #else
  344.         newid->next = 0;
  345.         if( !d_anchor)
  346.           { d_anchor = destructors = newid; }
  347.         else
  348.           {
  349.               destructors->next = newid;
  350.               destructors = newid;
  351.           }
  352. #endif
  353.         }
  354.       else if ( ! need_cdtor_list &&
  355.            /* this shows we have ccrt0 and need the C/DTOR_LISTs */
  356.            (! strncmp (p, FUNCTION_LIST_ADDR, FUNCTION_LIST_ADDR_LEN)))
  357.         need_cdtor_list ++;
  358.       }
  359.  
  360.     if ( ! need_cdtor_list && constructors == 0 && destructors == 0 ) return 0;
  361.     
  362.     if (! (CDTOR_file = fopen (CDTOR_filename_c, "w")))
  363.       ERROR( "fopen failed");
  364.     
  365.     /* Write the tables as C code  */
  366.     fprintf (CDTOR_file, "typedef void entry_pt();\n\n");
  367.     
  368.     write_list (CDTOR_file, "entry_pt ", constructors, ";\n");
  369.     
  370.     fprintf (CDTOR_file, "\nentry_pt * __CTOR_LIST__[] = {\n");
  371. #ifdef OLD_FORMAT
  372.     fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_constructors);
  373.     write_list (CDTOR_file, "\t", constructors, ",\n");
  374. #else
  375.     write_list (CDTOR_file, "\t", constructors, ",\n");
  376. #endif
  377.     fprintf (CDTOR_file, "\t0\n};\n\n");
  378.  
  379. #ifdef OLD_FORMAT    
  380.     write_list (CDTOR_file, "entry_pt ", destructors, ";\n");
  381. #else
  382.      write_list (CDTOR_file, "entry_pt ", d_anchor, ";\n");
  383. #endif
  384.  
  385.     fprintf (CDTOR_file, "\nentry_pt * __DTOR_LIST__[] = {\n");
  386. #ifdef OLD_FORMAT
  387.     fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_destructors);
  388.     write_list (CDTOR_file, "\t", destructors, ",\n");
  389. #else
  390.     write_list (CDTOR_file, "\t", d_anchor, ",\n");
  391. #endif
  392.     fprintf (CDTOR_file, "\t0\n};\n\n");
  393.     
  394.     if (fclose (CDTOR_file))
  395.       ERROR( "fclose failed");
  396.     
  397.     return 1;
  398. }
  399.  
  400.  
  401. write_list ( FILE *CDTOR_file, char * prefix, struct id *list, char * suffix)
  402.      /* 
  403.       * Write `prefix', the names on list LIST, `suffix'.
  404.       */
  405. {
  406.     if (! list)
  407.       return;
  408.     write_list ( CDTOR_file, prefix, list->next, suffix);
  409.     fprintf ( CDTOR_file, "%s%s%s", prefix, list->name, suffix);
  410. }
  411.  
  412.  
  413. static void error( const char * msg, int line )
  414. {
  415.     static char buf[BUFSIZ];
  416.     sprintf( buf, "%s: %s at %d", prog_name, S(msg), line);
  417.     perror( buf);
  418.     exit( 1);
  419. }
  420.  
  421.  
  422. /* FIXME: the -r option should be enabled (maybe with a flag) on certain machines */
  423. /* FIXME: no fixed size arrays should be used, but xmalloc (see collect-osf) */
  424. /* FIXME: check why const does not work */
  425. /* FIXME: encapsulate prototypes */
  426. /* FIXME: make all external interface names configureable */
  427.